package org.oschina.api.software.service;

import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.oschina.Config;
import org.oschina.Constants;
import org.oschina.Message;
import org.oschina.Module;
import org.oschina.ResultUtil;
import org.oschina.api.BaseService;
import org.oschina.api.manage.config.service.ConfigService;
import org.oschina.api.manage.module.ModuleType;
import org.oschina.api.manage.module.vo.ModuleVo;
import org.oschina.api.software.SoftwareType;
import org.oschina.api.software.dao.SoftwareDAO;
import org.oschina.api.software.model.Software;
import org.oschina.api.software.vo.SoftwareAccessVo;
import org.oschina.api.software.vo.SoftwareVo;
import org.oschina.api.user.active.UserActiveType;
import org.oschina.api.user.active.service.UserActiveService;
import org.oschina.api.user.role.service.UserRoleService;
import org.oschina.api.user.user.model.User;
import org.oschina.api.user.user.service.UserService;
import org.oschina.api.user.user.vo.UserVo;
import org.oschina.bean.Pager;
import org.oschina.bean.Result;
import org.oschina.helper.index.IndexResultBean;
import org.oschina.api.favorite.favorite.service.FavoriteService;
import org.oschina.api.favorite.type.FavoriteType;
import org.oschina.api.index.service.IndexService;
import org.oschina.security.AuthenticationException;
import org.oschina.security.ISecurity;
import org.oschina.security.annotation.Require;
import org.oschina.util.DateUtil;
import org.oschina.util.ListUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SoftwareService extends BaseService {

	@Autowired
	private SoftwareDAO softwareDAO;
	@Autowired
	private UserService userService;
	@Autowired
	private IndexService indexService;
	@Autowired
	private ConfigService configService;
	@Autowired
	private UserRoleService roleService;
	@Autowired
	private ISecurity security;
	@Autowired
	private UserActiveService userActiveService;
	@Autowired
	private FavoriteService favoriteService;
	
	/**
	 * 关注
	 * @param id
	 * @return
	 */
	@Require
	public Result createFavorite(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		if(softwareVo==null || !_isSimple(softwareVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		User user=userService.getAuthenticationInfo(getToken());
		Result result=favoriteService.create(user.getId(),softwareVo.getTitle(), id, FavoriteType.SOFTWARE);
		
		if(result.isSuccess())
			_updateFavoriteCount_plus(softwareVo);
		
		return result;
	}
	
	/**
	 * 删除关注
	 * @param id
	 * @return
	 */
	@Require
	public Result deleteFavorite(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		if(softwareVo==null || !_isSimple(softwareVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		User user=userService.getAuthenticationInfo(getToken());
		Result result=favoriteService.delete(user.getId(), id, FavoriteType.SOFTWARE);
		
		if(result.isSuccess())
			_updateFavoriteCount_minus(softwareVo);
		
		return result;
	}
	/**
	 * 设置推荐
	 * @param id
	 * @return
	 */
	@Require(authorization=Module.MODULE_22)
	public Result setRecommend(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		if(softwareVo==null)
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		if(_isRecommend(softwareVo))
			_setRecommend(softwareVo, 0);
		else
			_setRecommend(softwareVo,DateUtil.now());
			
		return ResultUtil.getSuccess(Message.UPDATE_SUCCESS);
	}
	
	/**
	 * 编辑
	 * @param software
	 * @return
	 */
	@Require
	public Result edit(Software software)
	{
		SoftwareVo softwareVo=_findVoById(software.getId());
		if(softwareVo==null || !_isSimple(softwareVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		if(!security.require(new String[]{Module.MODULE_23}, getToken(), false))
		{
			User user=userService.getAuthenticationInfo(getToken());
			if(!_isAuthor(user,softwareVo) || !security.require(new String[]{Module.MODULE_24},getToken(), false))
				throw new AuthenticationException();
		}
		
		_edit(software);
		setCheck(softwareVo);
		return ResultUtil.getSuccess(software);
	}
	
	/**
	 * 创建
	 * @param software
	 * @return
	 */
	@Require(authorization=Module.MODULE_12)
	public Result create(Software software)
	{
		SoftwareVo softwareVo=_findVoByName(software.getName());
		if(softwareVo!=null)
			return ResultUtil.getFailure(Message.SOFTWARE_ERROR_IS_EXIST);
		
		software=_create(software,userService.getVo(getToken()));
		userActiveService.create(software.getId(),software.getName(),null,UserActiveType.SOFTWARE);
		return ResultUtil.getSuccess(software);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public SoftwareAccessVo findById(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		
		if(softwareVo==null || !_isSimple(softwareVo))
			return null;

		SoftwareAccessVo softwareAccessVo=new SoftwareAccessVo();
		softwareAccessVo.setSoftware(softwareVo);
		
		User user=userService.getAuthenticationInfo(getToken());
		if(user!=null)
		{
			softwareAccessVo.setFavorite(favoriteService._isFavorite(user.getId(), id, FavoriteType.SOFTWARE));
			List<ModuleVo> module=roleService._findVoByRoleAndType(user, ModuleType.MODULE_9);
			if(_isAuthor(user, softwareVo))
			{
				module.addAll(roleService._findVoByRoleAndType(user, ModuleType.MODULE_8));
				module=ListUtil.removeRepeat(module);
			}
			softwareAccessVo.setModule(module);
		}
		
		return softwareAccessVo;
	}
	
	/**
	 * 返回最新推荐
	 * @param pn
	 * @return
	 */
	public Pager<SoftwareVo> findVoOrderRecommend(int pn)
	{
		Pager<SoftwareVo> pager=new Pager(pn,_getCountByTypeOrderRecommend(SoftwareType.SIMPLE),_getPageCount(),null);
		if(pager.getData_sum()>0)
			pager.setData(_findVoByTypeOrderRecommend(SoftwareType.SIMPLE, pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 返回首页最新推荐
	 * @return
	 */
	public List<SoftwareVo> findVoOrderRecommendIndex()
	{
		return _findVoByTypeOrderRecommend(SoftwareType.SIMPLE, 0, (Integer)configService.getValueById(Config.CONFIG_14, Integer.class));
	}
	
	/**
	 * 更新
	 * @param software
	 * @return
	 */
	@Require(authorization=Module.MODULE_13)
	public Result update(Software software)
	{
		if(_update(software)==0)
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		return ResultUtil.getSuccess(software);
	}
	
	/**
	 * 返回正在审核的
	 * @param pn
	 * @return
	 */
	@Require(authorization=Module.MODULE_13)
	public Pager<SoftwareVo> findCheck(int pn)
	{
		Pager<SoftwareVo> pager=new Pager(pn,_getCountByType(SoftwareType.CHECK),_getPageCount(),null);
		if(pager.getData_sum()>0)
			pager.setData(_findVoByType(SoftwareType.CHECK, pager.getStart(), pager.getPage_count()));
		
		return pager;
	}
	
	/**
	 * 审核通过
	 * @param id
	 * @return
	 */
	@Require(authorization=Module.MODULE_13)
	public Result checkPass(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		if(softwareVo==null || !_isCheck(softwareVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);

		_setSimple(softwareVo);
		return ResultUtil.getSuccess(Message.CHECK_SUCCESS);
	}
	
	/**
	 * 审核失败
	 * @param id
	 * @return
	 */
	@Require(authorization=Module.MODULE_13)
	public Result checkFailure(int id)
	{
		SoftwareVo softwareVo=_findVoById(id);
		if(softwareVo==null || !_isCheck(softwareVo))
			return ResultUtil.getFailure(Message.ERROR_DATA_ERROR);
		
		_setDelete(softwareVo);
		return ResultUtil.getSuccess(Message.DELETE_SUCCESS);
	}
	
	/**
	 * 根据搜索返回
	 * @param keywords
	 * @param first
	 * @param max
	 * @return
	 */
	public Pager<SoftwareVo> findVoBySearch(String keyword,int pn)
	{
		String keywords[]=StringUtils.split(keyword," ");
		Pager pager=new Pager(pn,0,_getPageCount(),null);
		IndexResultBean indexResult=_searchVoByType(keywords,SoftwareType.SIMPLE, pager.getStart(), pager.getPage_count());
		pager.setData_sum(indexResult.getSum());
		pager.setData(indexResult.getResult());
		return pager;
	}
	
	/**
	 * 根据类型搜索
	 * @param keywords
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	private IndexResultBean<SoftwareVo> _searchVoByType(String keywords[],int type,int first,int max)
	{
		return softwareDAO.searchVoByType(keywords, type,first, max);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public SoftwareVo _findVoById(int id)
	{
		return softwareDAO.findVoById(id);
	}
	
	/**
	 * 设置推荐
	 * @param softwareVo
	 * @return
	 */
	private int _setRecommend(SoftwareVo softwareVo,long time)
	{
		return softwareDAO.setRecommend(softwareVo, time);
	}
	/**
	 * 根据类型返回_根据推荐时间排序
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	private List<SoftwareVo> _findVoByTypeOrderRecommend(int type,int first,int max)
	{
		return softwareDAO.findVoByTypeOrderRecommend(type, first, max);
	}
	/**
	 * 根据类型返回数量_根据推荐时间
	 * @param type
	 * @return
	 */
	public int _getCountByTypeOrderRecommend(int type)
	{
		return softwareDAO.getCountByTypeOrderRecommend(type);
	}
	
	/**
	 * 根据名称返回
	 * @param name
	 * @return
	 */
	private SoftwareVo _findVoByName(String name)
	{
		return softwareDAO.findVoByName(name);
	}
	
	/**
	 * 编辑
	 * @param software
	 * @return
	 */
	private int _edit(Software software)
	{
		return softwareDAO.edit(software);
	}
	
	/**
	 * 更新
	 * @param software
	 * @return
	 */
	private int _update(Software software)
	{
		return softwareDAO.update(software);
	}
	
	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	private int _updateType(SoftwareVo softwareVo,int type)
	{
		return softwareDAO.updateType(softwareVo.getId(), type);
	}
	
	/**
	 * 根据类型返回数量
	 * @param type
	 * @return
	 */
	private int _getCountByType(int type)
	{
		return softwareDAO.getCountByType(type);
	}
	
	/**
	 * 根据type返回
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	private List<SoftwareVo> _findVoByType(int type,int first,int max)
	{
		return softwareDAO.findVoByType(type, first, max);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	private void _updateFavoriteCount_plus(SoftwareVo softwareVo)
	{
		softwareDAO.updateFavoriteCount(softwareVo.getId(), 1);
	}
	
	/**
	 * 更新关注数量
	 * @param id
	 * @param count
	 */
	private void _updateFavoriteCount_minus(SoftwareVo softwareVo)
	{
		softwareDAO.updateFavoriteCount(softwareVo.getId(), -1);
	}
	
	/**
	 * 创建
	 * @param software
	 * @param author
	 * @return
	 */
	private Software _create(Software software,UserVo author)
	{
		software.setId(_getIndex());
		software.setAuthor(author.getId());
		software.setType(SoftwareType.CHECK);
		software.setTitle(software.getName());
		software.setIcon(_getDefaultIcon());
		software.setRecommend_time(0L);
		software.setFavorite_count(0);
		software.setCreate_time(DateUtil.now());
		softwareDAO.create(software);
		return software;
	}
	
	/**
	 * 是否普通
	 * @param software
	 * @return
	 */
	private boolean _isSimple(SoftwareVo software)
	{
		return (software.getType().equals(SoftwareType.SIMPLE));
	}
	
	/**
	 * 是否正在审核
	 * @param software
	 * @return
	 */
	private boolean _isCheck(SoftwareVo software)
	{
		return (software.getType().equals(SoftwareType.CHECK));
	}
	
	/**
	 * 是否已删除
	 * @param software
	 * @return
	 */
	private boolean _isDelete(SoftwareVo software)
	{
		return (software.getType().equals(SoftwareType.DELETE));
	}
	
	private int _getPageCount()
	{
		return (Integer) configService.getValueById(Config.CONFIG_7, Integer.class);
	}
	
	private int _getIndex()
	{
		return indexService.getMajorById(Constants.INDEX_SOFTWARE);
	}
	
	private String _getDefaultIcon()
	{
		return (String) configService.getValueById(Config.CONFIG_13, String.class);
	}
	
	/**
	 * 是否是作者
	 * @param user
	 * @param softwareVo
	 * @return
	 */
	private boolean _isAuthor(User user,SoftwareVo softwareVo)
	{
		return (softwareVo.getAuthor().getId().equals(user.getId()));
	}
	
	/**
	 * 是否推荐
	 * @param softwareVo
	 * @return
	 */
	private boolean _isRecommend(SoftwareVo softwareVo)
	{
		return (softwareVo.getRecommend_time()!=null && softwareVo.getRecommend_time()!=0);
	}
	
	private void _setSimple(SoftwareVo softwareVo)
	{
		_updateType(softwareVo,SoftwareType.SIMPLE);
	}
	
	private void setCheck(SoftwareVo softwareVo)
	{
		_updateType(softwareVo,SoftwareType.CHECK);
	}
	
	private void _setDelete(SoftwareVo softwareVo)
	{
		_updateType(softwareVo,SoftwareType.DELETE);
	}
}